package com.ruoyi.message.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.constant.MeetMessage;
import com.ruoyi.common.constant.Openscreenshare;
import com.ruoyi.common.constant.PlayerData;
import com.ruoyi.common.constant.PlayerOut;
import com.ruoyi.message.handler.WebSocketHandler;
import com.ruoyi.message.service.WebSocketEndPoint;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import javax.websocket.Session;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author: 高飞
 * @time: 2023/12/2
 * @description: 一个会议
 **/
public class Room {
    private static final Logger log = LoggerFactory.getLogger(Room.class);

    public Room(Long roomId) {
        this.roomId = roomId;
    }

    private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    /**
     * 会议号
     */
    @Getter
    private final Long roomId;

    private final Map<Session, String> sessionNameMap = new ConcurrentHashMap<>();

    public List<PlayerData> listPlayer() {
        return sessionNameMap.values().stream().map(s -> new PlayerData(s, null)).collect(Collectors.toList());
    }

    /**
     * 是否正在共享屏幕
     */
    private boolean isScreen = false;

    /**
     * 最后一次的屏幕共享命令
     */
    private MeetMessage screenMessage;

    /**
     * 当前共享屏幕的用户名
     */
    private String screenUser;

    private AtomicBoolean isSending = new AtomicBoolean(false);

    public int peopleNum() {
        return sessionNameMap.size();
    }

    /**
     * 加入会议
     * author 高飞
     * time   2023/12/2
     * @param userName 用户名
     * @param session 链接
     */
    public void join(String userName, Session session) {
        sessionNameMap.put(session, userName);

        if (isScreen) {
            messageToUser(session, screenMessage);
        }
    }

    /**
     * 离开会议
     * author 高飞
     * time   2023/12/2
     * @param session 链接
     */
    public synchronized void leave(Session session) {
        String name = sessionNameMap.remove(session);
        if (Objects.isNull(name)) {
            return;
        }

        MeetMessage meetMessage = new MeetMessage();
        meetMessage.setType("playerout");
        meetMessage.setMsg(new PlayerOut(name, roomId.intValue()));
        messageToOther(session, meetMessage);

        if (isScreen && name.equals(screenUser)) {
            Openscreenshare meet = new Openscreenshare(roomId, name, false);
            this.screenMessage.setMsg(meet);
            messageToOther(session, this.screenMessage);
            this.screenMessage = null;
            isScreen = false;
            screenUser = null;
        }
    }

    /**
     * 开启或关闭共享屏幕命令
     * author 高飞
     * time   2023/12/2
     * @param session 链接
     */
    public void beginScreenShare(Session session, MeetMessage meetMessage) {
        String userName = sessionNameMap.get(session);
        if (Objects.isNull(userName)) {
            return;
        }

        Openscreenshare meet = OBJECT_MAPPER.convertValue(meetMessage.getMsg(), Openscreenshare.class);
        if (meet.getIsopen()) {
            // 打开共享，如果是自己打开的，并且曾经打开过
            if (isScreen && userName.equals(screenUser)) {
                messageToUser(session, meetMessage);
            }
            // 别人打开了
            else if (isScreen) {
                messageToUser(session, screenMessage);
            }
            else {
                isScreen = true;
                screenUser = userName;
                // 没人开过
                this.screenMessage = meetMessage;
                messageToAll(meetMessage);
            }
        }
        else {
            // 打开共享，如果是自己打开的，并且曾经打开过
            if (isScreen && userName.equals(screenUser)) {
                isScreen = false;
                this.screenMessage = meetMessage;
                messageToAll(meetMessage);
            }
        }
    }

    private void messageToUser(Session session, MeetMessage meetMessage) {
        String msg = null;
        try {
            msg = OBJECT_MAPPER.writeValueAsString(meetMessage);
        }
        catch (Exception e) {
            return;
        }

        WebSocketHandler.sendMessage(session, msg);
    }

    /**
     * 在此只表示屏幕共享数据
     * author 高飞
     * time   2023/12/2
     * @param session session
     * @param bytes bytes
     */
    public void binMessage(Session session, byte[] bytes) {
        synchronized (this) {
            if (isSending.get()) {
                return;
            }
            isSending.set(true);
        }
        messageToOther(session, bytes);
        synchronized (this) {
            isSending.set(false);
        }
    }

    /**
     * 发送消息给除本人外的其他用户
     * author 高飞
     * time   2023/12/2
     * @param session session
     * @param meetMessage meetMessage
     */
    public void messageToOther(Session session, MeetMessage meetMessage) {
        String msg = null;
        try {
            msg = OBJECT_MAPPER.writeValueAsString(meetMessage);
        }
        catch (Exception e) {
            return;
        }

        List<Session> sessionsList = getOtherSessionsByRoomId(session);
        if (CollectionUtils.isEmpty(sessionsList)) {
            return;
        }

        String finalMsg = msg;
        sessionsList.parallelStream().forEach(session1 -> WebSocketHandler.sendMessage(session1, finalMsg));
    }

    /**
     * 发送消息给除本人外的其他用户
     * author 高飞
     * time   2023/12/2
     * @param session session
     */
    public void messageToOther(Session session,byte[] bytes) {
        List<Session> sessionsList = getOtherSessionsByRoomId(session);
        if (CollectionUtils.isEmpty(sessionsList)) {
            return;
        }

        sessionsList.parallelStream().forEach(session1 -> WebSocketHandler.sendBinary(session1, bytes));
    }

    /**
     * 发送消息给除所有用户
     * author 高飞
     * time   2023/12/2
     * @param meetMessage meetMessage
     */
    public void messageToAll(MeetMessage meetMessage) {
        String msg = null;
        try {
            msg = OBJECT_MAPPER.writeValueAsString(meetMessage);
        }
        catch (Exception e) {
            return;
        }

        List<Session> sessionsList = getAllSessions();
        if (CollectionUtils.isEmpty(sessionsList)) {
            return;
        }

        String finalMsg = msg;
        sessionsList.parallelStream().forEach(session1 -> WebSocketHandler.sendMessage(session1, finalMsg));
    }

    private List<Session> getOtherSessionsByRoomId(Session session) {
        List<Session> sessionsList = new ArrayList<>();
        for (Session s : sessionNameMap.keySet()) {
            if (s.equals(session)) {
                continue;
            }
            sessionsList.add(s);
        }
        return sessionsList;
    }
    private List<Session> getAllSessions() {
        return new ArrayList<>(sessionNameMap.keySet());
    }
}
